package org.feng.utils;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.io.file.FileNameUtil;
import cn.hutool.core.util.IdUtil;
import com.alibaba.fastjson2.JSON;
import com.alibaba.fastjson2.JSONArray;
import com.alibaba.fastjson2.JSONObject;
import jakarta.servlet.ServletOutputStream;
import jakarta.servlet.http.HttpServletResponse;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.xssf.usermodel.*;

import java.io.File;
import java.io.FileOutputStream;
import java.util.*;

/**
 * poi工具类
 *
 * @author : FengShuai
 * @since : 2024/2/1 9:32
 */
public class PoiUtils {
    /**
     * 导出excel到浏览器流
     */
    public static <T> void exportExcel(LinkedHashMap<String, String> params, List<T> data) {
        exportExcelStream(params, data);
    }

    /**
     * 导出excel到文件
     */
    public static <T> void exportExcel(LinkedHashMap<String, String> params, List<T> data, String filePath) {
        File file = FileUtil.file(filePath);
        exportExcelFile(params, data, filePath, FileNameUtil.mainName(file));
    }

    private static <T> void exportExcelStream(LinkedHashMap<String, String> params, List<T> data) {
        XSSFWorkbook workbook = new XSSFWorkbook();
        createSheet(workbook, "表格", params, data);
        try {
            HttpServletResponse response = HttpUtils.getResponse();
            response.setHeader("download-filename", IdUtil.getSnowflakeNextIdStr() + ".xlsx");
            ServletOutputStream outputStream = response.getOutputStream();
            workbook.write(outputStream);
            outputStream.flush();
            outputStream.close();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    private static <T> void exportExcelFile(LinkedHashMap<String, String> params, List<T> data, String filePath, String sheetName) {
        XSSFWorkbook workbook = new XSSFWorkbook();
        createSheet(workbook, sheetName, params, data);
        FileOutputStream fos;
        try {
            fos = new FileOutputStream(filePath);
            workbook.write(fos);
            fos.flush();
            fos.close();
        } catch (Exception e) {
            throw new RuntimeException(e.getMessage());
        }
    }

    private static <T> void createSheet(XSSFWorkbook workbook, String sheetName, LinkedHashMap<String, String> params, List<T> data) {
        XSSFCellStyle style = workbook.createCellStyle();
        style.setWrapText(true);
        XSSFSheet xssfSheet = workbook.createSheet(sheetName);
        List<String> headerList = new ArrayList<>();
        List<String> filedList = new ArrayList<>();
        makeHeaderAndParamsKey(headerList, filedList, params);
        createExcelHeaderRows(headerList, xssfSheet);
        fillExcelData(data, filedList, xssfSheet);
    }

    private static void makeHeaderAndParamsKey(List<String> headerList, List<String> filedList, LinkedHashMap<String, String> params) {
        Set<Map.Entry<String, String>> set = params.entrySet();
        for (Map.Entry<String, String> entry : set) {
            filedList.add(entry.getKey());
            headerList.add(entry.getValue());
        }
    }

    private static void createExcelHeaderRows(List<String> headerList, XSSFSheet xssfSheet) {
        XSSFRow row = xssfSheet.createRow(0);
        row.setHeight((short) 700);
        for (int i = 0; i < headerList.size(); i++) {
            XSSFCell cell = row.createCell(i, CellType.STRING);
            cell.setCellValue(headerList.get(i));
        }
    }


    private static <T> void fillExcelData(List<T> data, List<String> filedList, XSSFSheet xssfSheet) {
        JSONArray dataArray = JSONArray.parseArray(JSON.toJSONString(data));
        for (int j = 0; j < dataArray.size(); j++) {
            XSSFRow rows = xssfSheet.createRow(j + 1);
            rows.setHeight((short) 500);
            JSONObject d = JSON.parseObject(JSON.toJSONString(dataArray.get(j)));
            for (int k = 0; k < filedList.size(); k++) {
                XSSFCell cell = rows.createCell(k);
                String s = filedList.get(k);
                cell.setCellValue(d.get(s) == null ? "" : String.valueOf(d.get(s)));
            }
        }
        autoColumnSize(xssfSheet, data.size());
    }

    private static void autoColumnSize(XSSFSheet sheet, int size) {
        for (int i = 0; i < size; i++) {
            sheet.autoSizeColumn(i);
        }
        for (int columnNum = 0; columnNum < size; columnNum++) {
            int columnWidth = sheet.getColumnWidth(columnNum) / 256;
            for (int rowNum = 0; rowNum < sheet.getLastRowNum(); rowNum++) {
                XSSFRow currentRow;
                if (sheet.getRow(rowNum) == null) {
                    currentRow = sheet.createRow(rowNum);
                } else {
                    currentRow = sheet.getRow(rowNum);
                }
                if (currentRow.getCell(columnNum) != null) {
                    XSSFCell currentCell = currentRow.getCell(columnNum);
                    if (currentCell.getCellType() == CellType.STRING) {
                        int length = currentCell.getStringCellValue().getBytes().length;
                        if (columnWidth < length) {
                            columnWidth = length;
                        }
                    }
                }
            }
            sheet.setColumnWidth(columnNum, columnWidth * 256);
        }

    }
}
